#!/usr/bin/env python
# Purpose: XML import for HydroPlatform
# Created: September 2012
# Copyright (c) 2012 by University College London
# Author:
#  Hossam Almeer <halmeer@ucl.cs.ac.uk>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with HydroPlatform for details.

import codecs
from itertools import count, chain
import logging
import numpy
import os
import sets

import time

from sqlalchemy import and_

from hydroplatform.model.export import Exporter, ExportError, ExporterRegistry
from hydroplatform.model import network as nt
from hydroplatform.model import fields as fd
from hydroplatform.model import units
from hydroplatform.model.fields import Parameter

from xml_parse import parse_par_file


'''
Imports XML files. XML files that are imported by this module are only
importable if the have been exported by the xml exporter. Any changes besides
changes to values will cause this importer to have unpredictable behaviour

For more info, see : hydroplatform.extension.export.xml_export
               and : hydroplatform.extension.export.xml_parse
'''


class XMLImport(Exporter):

    '''
    Import an XML file and update network with new values
    '''
    
    _name = "XML import"
    _description  = '''Imports an XML file, whether for node/link \
                       parameter/time_series/seasonal_parameters''' 
   
    def __init__(self):
        Exporter.__init__(self)
        self.session = None    
        

    def export(self, network, filename, session=None):
        '''
        Import the XML file
        '''

        def is_param(obj_field):
            return isinstance( obj_field.attribute_type, Parameter)

        def update_node_params(node,xml_node):
            '''
            Nested function which updates the values of an internal node 
            with imported parameter values
            '''
            assert node.id == xml_node.id # I don't like assert,but it's needed
            for fd in node.type.fields:
                if is_param(fd):
                    val = node.getFieldValue(session, fd)
                    if val:
                        val.value = xml_node.data[fd.name]
                    # Order of magnitude speedup if using flush() vs commit()
                        session.flush()
                    else:
                        continue
                        
        # Tried codecs.open(), functions choked on the unicode as 
        # split() behaves differently
        temp_file = open('temp_file.xml','w+')
        infile    = open(filename, 'r')

        network_name,all_nodes = parse_par_file(infile,temp_file)

        if not network_name:
            raise Exception('File is not a valid format')
            return

 
        if not (network_name[1:-2] in network.name): # net_name still has <,>
             raise NameError('Network name mismatch\nIt seems this XML \
                             file is referring to a different network')
             return

        x_nodes = dict()  # Hash of nodes that have any parameters, id:XMLNode
        for i in all_nodes:
            if i.data:   x_nodes[i.id] = i
 
        for node in network.nodes:
            try:
                xn = x_nodes[node.id]
                update_node_params(node,xn)
            except KeyError:
                continue

        session.commit()


REGISTRY = ExporterRegistry()
REGISTRY.register(XMLImport)
logging.info("XMLImport extension registered")        
